#ifndef __LOG_H_
#define __LOG_H_
//日志系统
//支持自定义Appender
//不支持自定义formater
#include <memory>
#include <sstream>
#include <vector>
#include <list>
#include <stdint.h>
#include <string>
#include <fstream>
#include <map>

#include "util.h"
#include "fiber.h"
#include "thread.h"

#define LEARNCO_LOG_LEVEL(logger, level) \
    if(logger->getLevel() <= level) \
        learnco::LogEventWrap(learnco::LogEvent::ptr(new learnco::LogEvent(logger, level, \
                        __FILE__, __LINE__, 0, learnco::GetThreadId(),\
                learnco::GetFiberID(), time(0), learnco::Thread::GetName()))).getSS()


#define LEARNCO_LOG_DEBUG(logger) LEARNCO_LOG_LEVEL(logger, learnco::LogLevel::DEBUG)
#define LEARNCO_LOG_INFO(logger)  LEARNCO_LOG_LEVEL(logger, learnco::LogLevel::INFO)
#define LEARNCO_LOG_WARN(logger)  LEARNCO_LOG_LEVEL(logger, learnco::LogLevel::WARN)
#define LEARNCO_LOG_ERROR(logger) LEARNCO_LOG_LEVEL(logger, learnco::LogLevel::ERROR)
#define LEARNCO_LOG_FATAL(logger) LEARNCO_LOG_LEVEL(logger, learnco::LogLevel::FATAL)

namespace learnco {

class Logger;

//日志级别
class LogLevel{
public:
    enum Level {
        UNKNOW = 0,
        DEBUG = 1,
        INFO = 2,
        WARN = 3,
        ERROR = 4,
        FATAL = 5
    };

    static const char* ToString(LogLevel::Level level);
};

//日志事件 
class LogEvent{
public:
    typedef std::shared_ptr<LogEvent> ptr;
    LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level
            ,std::string file, int32_t line, uint32_t elapse
            ,uint32_t thread_id, uint32_t fiber_id, uint64_t time
            ,const std::string& thread_name);
        
private:
    std::string m_file = nullptr;  //文件名
    int32_t m_line = 0;            //行号
    uint32_t m_elapse = 0;         //程序启动开始到现在的毫秒数
    uint32_t m_threadId = 0;       //线程id
    uint32_t m_fiberId = 0;        //协程id
    uint64_t m_time = 0;           //时间戳
    std::string m_threadName;      //线程名称

    std::stringstream m_ss;        
    std::shared_ptr<Logger> m_logger;
    LogLevel::Level m_level;

public:
    int32_t getLine() const { return m_line;}
    uint32_t getElapse() const { return m_elapse;}
    uint32_t getThreadId() const { return m_threadId;}
    uint32_t getFiberId() const { return m_fiberId;}
    uint64_t getTime() const { return m_time;}
    const std::string& getThreadName() const { return m_threadName;}

    const std::string getFile() const { 
        int i = m_file.length()-1;
        for(; i>=0; --i){
            if(m_file[i] == '/') {
                break;
            }
        }
        return m_file.substr(i);
    }

    std::string getContent() const { return m_ss.str();}
    std::shared_ptr<Logger> getLogger() const { return m_logger;}
    LogLevel::Level getLevel() const { return m_level;}
    std::stringstream& getSS() { return m_ss;}
};


//日志格式器
/* 
 *  确定日志输出格式
 */
class LogFormatter {
public:
    static std::string format(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event);
};

//日志输出器
/* 
 *1.Effective C++07:为多态基类声明virtual析构函数
 */
class LogAppender {
public:
    typedef std::shared_ptr<LogAppender> ptr;
    virtual ~LogAppender() {}

protected:
    LogLevel::Level m_level = LogLevel::DEBUG;

public:
    virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;
    
    void setLevel(LogLevel::Level val) { m_level = val;}
    LogLevel::Level getLevel() const { return m_level;}
};


//日志器
class Logger : public std::enable_shared_from_this<Logger> {
friend class LoggerManager;
public:
    typedef std::shared_ptr<Logger> ptr;
    Logger(const std::string& name = "root");

private:
    std::string m_name;                     //日志名称
    LogLevel::Level m_level;                //日志级别
    std::list<LogAppender::ptr> m_appenders;//Appender集合
    Logger::ptr m_root;

public:
    void addAppender(LogAppender::ptr appender);
    void delAppender(LogAppender::ptr appender);
    void clearAppenders();

    LogLevel::Level getLevel() const { return m_level;}
    const std::string& getName() const { return m_name;}
    
    void log(LogLevel::Level level, LogEvent::ptr event);
    
};

//定义输出到文件的Appender
class FileLogAppender : public LogAppender {
public:
    typedef std::shared_ptr<FileLogAppender> ptr;
    FileLogAppender(const std::string& filename);
    
    //重新打开文件，文件打开成功返回true
    bool reopen();
    void log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override;
private:
    std::string m_filename;
    std::ofstream m_filestream;
    uint64_t m_lastTime = 0;
};

//输出到控制台的Appender
class StdoutLogAppender : public LogAppender {
public:
    typedef std::shared_ptr<StdoutLogAppender> ptr;
    void log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override;
};

//日志器 管理器. 单例模式：整个系统只允许存在一个日志管理器
class LoggerManager{
public:
    LoggerManager();
private:
    std::map<std::string, Logger::ptr> m_loggers;
    Logger::ptr m_root;

public:
    Logger::ptr getLogger(const std::string& name);
    Logger::ptr getRoot() const { return m_root;}
};


//单例模式 
//静态保证线程安全
template<class T>
class Singleton {
public:
    static T* GetInstance() {
        static T v;
        return &v;
    }
private:
    Singleton() = delete;
    ~Singleton() = delete;
};

typedef Singleton<LoggerManager> LoggerMgr;

//事件包装器
class LogEventWrap {
public:
    LogEventWrap(LogEvent::ptr e);
    ~LogEventWrap();
private:
    LogEvent::ptr m_event;
public:
    LogEvent::ptr getEvent() const { return m_event;}
    std::stringstream& getSS();
};

}


#endif
